home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland Pascal with Objects 7.0 / SHELLDEM.ZIP / SHELLDEM.PAS next >
Pascal/Delphi Source File  |  1992-10-27  |  11KB  |  364 lines

  1. {***************************************************}
  2. {                                                   }
  3. {   Windows 3.1 ShellAPI / Drag-and-Drop            }
  4. {   Demonstration Program                           }
  5. {   Copyright (c) 1992 by Borland International     }
  6. {                                                   }
  7. {***************************************************}
  8.  
  9. program ShellDemo;
  10.  
  11. {
  12.  This demo program implements a simple program-manager type application
  13.  using Drag & Drop and the SHELL API calls.
  14.  
  15.  Open this program on the Windows 3.1 desktop, and then drag files from the
  16.  File Manager onto this application's window.  The dropped-in files will 
  17.  appear as Icons in the window's client area, and double-clicking on those
  18.  Icons will execute the corresponding program.
  19. }
  20.  
  21. uses Strings, WinTypes, WinProcs, OWindows, ODialogs, Win31, ShellAPI, BWCC;
  22.  
  23. {$R SHELLDEM}
  24.  
  25. const
  26.  
  27. { Resource IDs }
  28.  
  29.   id_Menu  = 100;
  30.   id_About = 100;
  31.   id_Instr = 101;   { Instructions }
  32.   id_Icon  = 100;
  33.  
  34. { Menu command IDs }
  35.  
  36.   cm_HelpAbout = 300;
  37.   cm_HelpInstr = 301;
  38.  
  39. type
  40.  
  41. { Filename string }
  42.  
  43.   TFilename = array[0..255] of Char;
  44.  
  45. { Application main window }
  46.  
  47.   PDropTargetWin = ^TDropTargetWin;
  48.   TDropTargetWin = object(TWindow)
  49.     destructor Done; virtual;
  50.  
  51.     procedure GetWindowClass(var AWndClass: TWndClass); virtual;
  52.     function  GetClassName: PChar; virtual;
  53.     procedure SetupWindow; virtual;
  54.  
  55.     procedure WMDropFiles(var Msg: TMessage);
  56.       virtual wm_First + wm_DropFiles;
  57.  
  58.     procedure CMHelpAbout(var Msg: TMessage);
  59.       virtual cm_First + cm_HelpAbout;
  60.     procedure CMHelpInstructions(var Msg: TMessage);
  61.       virtual cm_First + cm_HelpInstr;
  62.  
  63. { Override this function in descendant classes to change behavior: }
  64.  
  65.     procedure DropAFile(FileName: PChar; DropX, DropY: Integer); virtual;
  66.   end;
  67.  
  68. { Icon Window }
  69.  
  70.   PIconWindow = ^TIconWindow;
  71.   TIconWindow = object(TWindow)
  72.     AppIcon   : HIcon;
  73.     HasOwnIcon: Boolean;  { True if icon found, False if default used }
  74.     Path      : PChar;
  75.     X, Y      : Integer;
  76.  
  77.     constructor Init(AParent: PWindowsObject; ATitle: PChar; DropX, DropY: Integer);
  78.     destructor  Done; virtual;
  79.  
  80.     procedure Paint(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  81.     procedure GetWindowClass(var AWndClass: TWndClass); virtual;
  82.     function  GetClassName: PChar; virtual;
  83.  
  84.     procedure WMQueryDragIcon(var Msg: TMessage);
  85.       virtual wm_First + wm_QueryDragIcon;
  86.     procedure WMQueryOpen(var Msg: TMessage);
  87.       virtual wm_First + wm_QueryOpen;
  88.     procedure WMSysCommand(var Msg: TMessage);
  89.       virtual wm_First + wm_SysCommand;
  90.   end;
  91.  
  92. { Application object }
  93.  
  94.   TShellApp = object(TApplication)
  95.     procedure InitMainWindow; virtual;
  96.   end;
  97.  
  98. { Initialized globals }
  99.  
  100. const
  101.   DemoTitle: PChar = 'Shell Demo Program';
  102.  
  103. { Global variables }
  104.  
  105. var
  106.   App: TShellApp;
  107.  
  108.  
  109. { TIconWindow Methods }
  110.  
  111. { Constructs an instance of an IconWindow.  These are child windows to the
  112.   main ShellAPI window which represent dropped files.  IconWindows always
  113.   represent themselves as Iconic.  The Icon to be used is extracted from
  114.   the application (as represented by its Title); if none can be found, the
  115.   idi_Question icon is used.  The IconWindow positions itself at the given
  116.   location.
  117. }
  118. constructor TIconWindow.Init(AParent: PWindowsObject; ATitle: PChar; DropX, DropY: Integer);
  119. var
  120.   FileName: PChar;
  121.   Temp    : TFilename;
  122.   ExeHdl  : THandle;
  123. begin
  124. { Set the Path data field to the full pathname for later use in executing
  125.   the program.  The passed-in title contains the complete path name of the
  126.   file, which we just copy.  Then, strip off just the filename portion, and
  127.   use that as the actual title for the icon, which is the Title field we
  128.   pass into the ancestral constructor.
  129. }
  130.   Path    := StrNew(ATitle);
  131.   FileName:= StrRScan(Path, '\');
  132.  
  133.   if (FileName <> nil) then
  134.   begin
  135.     if (FileName^ = '\') then
  136.       inc(FileName);  { Skip past the '\' }
  137.   end
  138.   else
  139.     FileName := ATitle;      { Just in case ... }
  140.  
  141.   inherited Init(AParent, FileName);
  142.   Attr.Style := Attr.Style or (ws_Minimize or ws_Child);
  143.  
  144. { Extract an Icon from the executable file.  If none is found, then just
  145.   use idi_Question.
  146. }
  147.   ExeHdl := FindExecutable(Path, '.\', Temp);
  148.  
  149.   if ExeHdl <= 32 then
  150.     AppIcon := 0
  151.   else
  152.     AppIcon := ExtractIcon(HInstance, Temp, 0);
  153.  
  154.   if AppIcon <= 1 then
  155.   begin
  156.     AppIcon   := LoadIcon(0, idi_Question);
  157.     HasOwnIcon:= True;
  158.   end
  159.   else
  160.     HasOwnIcon:= False;
  161.  
  162. { Set the x/y position of drop (in Parent coordinates).  This is
  163.   not used in this demo app, but is included to support variations
  164.   through writing descendants.
  165. }
  166.   X := DropX;
  167.   Y := DropY;
  168. end;
  169.  
  170. { Destroys an instance of the IconWindow.  Frees the AppIcon (unless the
  171.   standard idi_Question was used), and disposes of the Path name string.
  172. }
  173. destructor TIconWindow.Done;
  174. begin
  175.   if HasOwnIcon then
  176.     FreeResource(AppIcon);
  177.   StrDispose(Path);
  178.   inherited Done;
  179. end;
  180.  
  181. { Redefines GetWindowClass to give this application a NULL Icon.  This
  182.   is necessary so that Windows gives this application a chance to paint
  183.   its own icon when the window is Iconic.  When the hIcon field of AWndClass
  184.   is NULL, this window will receive wm_QueryDragIcon messages.
  185. }
  186. procedure TIconWindow.GetWindowClass(var AWndClass: TWndClass);
  187. begin
  188.   inherited GetWindowClass(AWndClass);
  189.   AWndClass.hIcon := 0;
  190. end;
  191.  
  192. { Returns the class name of this window.  This is necessary since we
  193.   redefine the inherited GetWindowClass method, above.
  194. }
  195. function TIconWindow.GetClassName: PChar;
  196. begin
  197.   GetClassName := 'TIconWindow';
  198. end;
  199.  
  200. { Responds to double-clicks on the Icon by executing the associated program.
  201.   Windows sends an iconified window a wm_QueryOpen message when
  202.   double-clicked. Overriding here allows us to completely redefine that
  203.   behavior. Uses the Path data field as the name of the program to execute.
  204. }
  205. procedure TIconWindow.WMQueryOpen(var Msg: TMessage);
  206. begin
  207.   ShellExecute(HWindow, nil, Path, '', '.\', sw_ShowNormal);
  208.  
  209.   Msg.Result := 0;  { Indicate that the message was handled }
  210. end;
  211.  
  212. { Returns the application's icon when the iconified window is dragged.  With
  213.   AWndClass.hIcon set to NULL, Windows asks for this whenever the drag is 
  214.   about to happen.
  215. }
  216. procedure TIconWindow.WMQueryDragIcon(var Msg: TMessage);
  217. begin
  218.   Msg.Result := AppIcon;
  219. end;
  220.  
  221. { Captures and filters out some variations on wm_SysCommand to prevent an
  222.   annoying 'beep' on single clicks on the icon.
  223. }
  224. procedure TIconWindow.WMSysCommand(var Msg: TMessage);
  225. begin
  226.   case (Msg.WParam and $FFF0) of
  227.     sc_MouseMenu: Msg.Result := 0;   { Indicate that the message was handled }
  228.     sc_KeyMenu  : Msg.Result := 0;
  229.   else
  230.     DefWndProc(Msg);
  231.   end;
  232. end;
  233.  
  234. { Responds to repaints of the window when requested.  With AWndClass.hIcon
  235.   set to NULL, Windows will let the window paint itself even when iconic.
  236.   NOTE that this is the 'new' way to draw you own icon, as opposed to 
  237.   wm_PaintIcon in Win3.0.
  238. }
  239. procedure TIconWindow.Paint(PaintDC: HDC; var PaintInfo: TPaintStruct);
  240. begin
  241.   DefWindowProc(HWindow, wm_IconEraseBkgnd, PaintDC, 0);
  242.   DrawIcon(PaintDC, 0, 0, AppIcon);
  243. end;
  244.  
  245.  
  246. { TDropTargetWin Methods }
  247.  
  248. { Destroys an instance of the Drop Target window.  Informs Windows that
  249.   this application will no longer accept Drop-File requests, then invokes
  250.   the ancestral destructor to complete the shutdown of the window.
  251. }
  252. destructor TDropTargetWin.Done;
  253. begin
  254.   DragAcceptFiles(HWindow, False);
  255.   inherited Done;
  256. end;
  257.  
  258. { Redefines GetWindowClass to give this application its own Icon, and
  259.   to identify the menu for this application.
  260. }
  261. procedure TDropTargetWin.GetWindowClass(var AWndClass: TWndClass);
  262. begin
  263.   inherited GetWindowClass(AWndClass);
  264.   AWndClass.hIcon        := LoadIcon(AWndClass.hInstance, MakeIntResource(id_Icon));
  265.   AWndClass.lpszMenuName := MakeIntResource(id_Menu);
  266.   AWndClass.hBrBackground:= GetStockObject(LtGray_Brush);
  267. end;
  268.  
  269. { Returns the class name of this window.  This is necessary since we
  270.   redefine the inherited GetWindowClass method, above.
  271. }
  272. function TDropTargetWin.GetClassName: PChar;
  273. begin
  274.   GetClassName := 'TDropTargetWin';
  275. end;
  276.  
  277. { Completes the initialization of the Icon window, by informing Windows
  278.   that this window will accept Drop-File requests.  This is deferred to
  279.   SetupWindow since it requires a valid window handle.  Note that
  280.   Shell.dll will flip the ws_Ex_AcceptFiles style bit for this window.
  281.  
  282.   Also posts the Instructions dialog automatically upon startup.
  283. }
  284. procedure TDropTargetWin.SetupWindow;
  285. begin
  286.   inherited SetupWindow;
  287.   DragAcceptFiles(HWindow, True);
  288.  
  289.   PostMessage(HWindow, wm_Command, cm_HelpInstr, 0);
  290. end;
  291.  
  292. { Responds to the dropping of a file onto this window.  Obtains the
  293.   dropped in file name(s), then calls the DropAFile method for each 
  294.   dropped file name.  The actual handling of the dropped file happens
  295.   there; it is separated from this method for ease of redefinition by
  296.   descendants.
  297. }
  298. procedure TDropTargetWin.WMDropFiles(var Msg: TMessage);
  299. var
  300.   DropPt     : TPoint;
  301.   hDrop      : THandle;
  302.   NumDropped : Integer;
  303.   DroppedName: TFilename;
  304.   I          : Integer;
  305. begin
  306.   hDrop := Msg.WParam;
  307.   DragQueryPoint(hDrop, DropPt);
  308.  
  309. { By passing in exactly these parameters, we get the number of files
  310.   (and directories) being dropped.
  311. }
  312.   NumDropped := DragQueryFile(hDrop, Word(-1), nil, 0);
  313.  
  314. { This time we pass in the 'real' parameters and SHELL.DLL will fill
  315.   in the path to the file (or directory).  Do so for each dropped file.
  316. }
  317.   for I := 0 to NumDropped-1 do
  318.   begin
  319.     DragQueryFile(hDrop, I, DroppedName, SizeOf(DroppedName));
  320.     DropAFile(DroppedName, DropPt.X, DropPt.Y);
  321.   end;
  322.  
  323.   DragFinish(hDrop);
  324. end;
  325.  
  326. { Actually handles the dropping of a file at a given point, by creating the
  327.   TIconWindow to represent that file.  Descendant classes can alter the be-
  328.   havior of this application by simply redefining this method.
  329. }
  330. procedure TDropTargetWin.DropAFile(FileName: PChar; DropX, DropY: Integer);
  331. begin
  332.   Application^.MakeWindow(New(PIconWindow, Init(@Self, FileName, DropX, DropY)));
  333. end;
  334.  
  335. { Posts the About Box for the Shell API Demo.
  336. }
  337. procedure TDropTargetWin.CMHelpAbout(var Msg: TMessage);
  338. begin
  339.   Application^.ExecDialog(New(PDialog, Init(@Self, PChar(id_About))));
  340. end;
  341.  
  342. { Posts the Instructions Box for the Shell API Demo.
  343. }
  344. procedure TDropTargetWin.CMHelpInstructions(var Msg: TMessage);
  345. begin
  346.   Application^.ExecDialog(New(PDialog, Init(@Self, PChar(id_Instr))));
  347. end;
  348.  
  349.  
  350. { TShellApp Methods }
  351.  
  352. procedure TShellApp.InitMainWindow;
  353. begin
  354.   MainWindow := New(PDropTargetWin, Init(nil, Application^.Name));
  355. end;
  356.  
  357. { Main program }
  358.  
  359. begin
  360.   App.Init(DemoTitle);
  361.   App.Run;
  362.   App.Done;
  363. end.
  364.